package autonomous;

import genetic.DNA;

import java.util.ArrayList;

import processing.core.PApplet;
import processing.core.PVector;

public class FlockPopulation extends PApplet {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	float mutationRate; // mutation rate
	ArrayList<DNA> darwin; // ArrayList which we will use for our "mating pool"
	int generations; // number of generations

	int countfinished; // keep track of the order of creature's finishing the
	float[] fitness;
	public Flock flock;
	PApplet parent;

	float speed;
	float force;

	// *INITIALIZE THE POPULATION*//
	public FlockPopulation(PApplet p, int dnasize, int m, int num, float ms,
			float mf) {

		parent = p;
		speed = ms;
		force = mf;
		mutationRate = m;
		darwin = new ArrayList<DNA>();
		generations = 0;
		// make a new set of creatures

		flock = new Flock();
		for (int i = 0; i < 8; i++)
			flock.addBoid(new FlockBoid(parent, new PVector(width / 2,
					height / 2), new DNA(dnasize), speed, force));

		countfinished = 1; // the first one to finish will be #1
	}

	public void live() {
		// For every creature
		// for (int i = 0; i < flock.size(); i++) {
		// if it finishes, mark it down as done!
		// if ((population[i].finished()) && (!population[i].stopped())) {
		// population[i].setFinish(countfinished);
		// countfinished++;
		// }
		// run it
		flock.run();
		// }
	}

	// // calculate fitness for each creature
	// public void calcFitness() {
	// for (int i = 0; i < population.length; i++) {
	// population[i].calcFitness();
	// }
	// countfinished = 1; // hmmm, awkward place for this, we have to reset
	// // this for the next generation
	// }

	// generate a mating pool
	public void naturalSelection() {
		// clear the ArrayList
		darwin.clear();

		// Calculate total fitness of whole population
		float totalFitness = getTotalFitness();
		//
		// // Calculate *normalized* fitness for each member of the population
		// // based on normalized fitness, each member will get added to the
		// mating
		// // pool a certain number of times a la roulette wheel
		// // a higher fitness = more entries to mating pool = more likely to be
		// // picked as a parent
		// // a lower fitness = fewer entries to mating pool = less likely to be
		// // picked as a parent
		for (int i = 0; i < flock.size(); i++) {

			float fitnessNormal = flock.getBoid(i).getFitness() / totalFitness;
			int n = (int) (fitnessNormal * 50000.0f);
			// print(n + " ");
			for (int j = 0; j < n; j++) {
				darwin.add(flock.getBoid(i).genes);
			}
		}
	}

	// *CREATE A NEW GENERATION**//
	public void generate() {
		// refill the population with children from the mating pool
//		for (int i = flock.size() - 1; i > 0; i--) {

			int m = (int) (random(flock.size()));
			int d = (int) (random(flock.size()));
			// pick two parents
			FlockBoid mom = flock.getBoid(m);
			FlockBoid dad = flock.getBoid(d);
			// get their genes
			DNA momgenes = mom.getGenes();
			DNA dadgenes = dad.getGenes();
			// mate their genes
			DNA child = momgenes.mate(dadgenes);
			// mutate their genes
			child.mutate(mutationRate);
			// fill the new population with the new child
			flock.addBoid(new FlockBoid(parent, new PVector(width / 2,
					height / 2), child, speed, force));

			// population[i] = new Creature(parent, target, new
			// PVector(start.r.x,
			// start.r.y), child, population.length);
//		}
		generations++;
	}

	public int getGenerations() {
		return generations;
	}

	// compute total fitness for the population
	float getTotalFitness() {
		float total = 0;
		for (int i = 0; i < flock.size(); i++) {
			total += flock.getBoid(i).getFitness();
		}
		return total;
	}

	// Compute average fitness for the population
	public float getAverageFitness() {
		float total = 0;
		for (int i = 0; i < flock.size(); i++) {
			total += fitness[i];
		}
		return total / (float) flock.size();
	}

}